#include "StdAfx.h"


void _log(string str)
{
	globals.Content.AddToLog(str);
}
void alert(string str)
{
	MessageBox(NULL, str, L"Error", MB_OK);
}
void TexCoord(Vec3 coords, unsigned int tex_unit)
{
	glMultiTexCoord3f(GL_TEXTURE0+tex_unit, coords.x, coords.y, coords.z);
}
void TexCoord(Vec2 coords, unsigned int tex_unit)
{
	glMultiTexCoord2f(GL_TEXTURE0+tex_unit, coords.x, coords.y);
}
Vec3 vMin(Vec3 v1, Vec3 v2)
{
	Vec3 vmin;
	vmin.x=std::min(v1.x, v2.x);
	vmin.y=std::min(v1.y, v2.y);
	vmin.z=std::min(v1.z, v2.z);
	return vmin;
}
Vec3 vMax(Vec3 v1, Vec3 v2)
{
	Vec3 vmax;
	vmax.x=std::max(v1.x, v2.x);
	vmax.y=std::max(v1.y, v2.y);
	vmax.z=std::max(v1.z, v2.z);
	return vmax;
}
void DrawCube(double size)
{
	DrawPrism(size,size,size);
}
void DrawFullScreenQuad()
{
	glBegin(GL_QUADS);
		glTexCoord2f(0.0, 0.0);
		glVertex2f(-1, -1);
		glTexCoord2f(1.0, 0.0);
		glVertex2f(1, -1);
		glTexCoord2f(1.0, 1.0);
		glVertex2f(1, 1);
		glTexCoord2f(0.0, 1.0);
		glVertex2f(-1, 1);
    glEnd();
}
void DrawQuad(double width, double numTiles)
{
	double hw=width/2.0;
	double tc=numTiles;
	glBegin(GL_QUADS);
		TexCoord(Vec2(0, tc),0);			//texture coordinates
		TexCoord(Vec3(1,0,0),1);			//tangent
		TexCoord(Vec3(0,0,1),2);			//bitangent
		Normal(Vec3(0,1,0));
		Vertex(Vec3(-hw,0,hw));

		TexCoord(Vec2(tc,tc),0);			//texture coordinates
		TexCoord(Vec3(1,0,0),1);			//tangent
		TexCoord(Vec3(0,0,1),2);			//bitangent
		Normal(Vec3(0,1,0));
		Vertex(Vec3(hw,0,hw));

		TexCoord(Vec2(tc, 0),0);			//texture coordinates
		TexCoord(Vec3(1,0,0),1);			//tangent
		TexCoord(Vec3(0,0,1),2);			//bitangent
		Normal(Vec3(0,1,0));
		Vertex(Vec3(hw,0,-hw));

		TexCoord(Vec2(0,0),0);				//texture coordinates
		TexCoord(Vec3(1,0,0),1);			//tangent
		TexCoord(Vec3(0,0,1),2);			//bitangent
		Normal(Vec3(0,1,0));
		Vertex(Vec3(-hw,0,-hw));		
	glEnd();
}
void DrawFloorBox(double width, double height, double ntiles, double nhtiles)
{
	DrawQuad(width, ntiles);
	double hw=width/2.0;
	double h=height;
	double htc=nhtiles;
	double tc=ntiles;
	glBegin(GL_QUADS);
		//left wall
		TexCoord(Vec2(0, htc),0);				//texture coordinates
		TexCoord(Vec3(0,0,1),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(1,0,0));
		Vertex(Vec3(-hw,h,-hw));

		TexCoord(Vec2(tc,htc),0);				//texture coordinates
		TexCoord(Vec3(0,0,1),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(1,0,0));
		Vertex(Vec3(-hw,h,hw));

		TexCoord(Vec2(tc, 0),0);			//texture coordinates
		TexCoord(Vec3(0,0,1),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(1,0,0));
		Vertex(Vec3(-hw,0,hw));

		TexCoord(Vec2(0,0),0);				//texture coordinates
		TexCoord(Vec3(0,0,1),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(1,0,0));
		Vertex(Vec3(-hw,0,-hw));	
		//right wall
		TexCoord(Vec2(0, htc), 0);			//texture coordinates
		TexCoord(Vec3(0,0,1),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(-1,0,0));
		Vertex(Vec3(hw,h,hw));

		TexCoord(Vec2(tc,htc), 0);			//texture coordinates
		TexCoord(Vec3(0,0,1),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(-1,0,0));
		Vertex(Vec3(hw,h,-hw));

		TexCoord(Vec2(tc, 0),0);			//texture coordinates
		TexCoord(Vec3(0,0,1),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(-1,0,0));
		Vertex(Vec3(hw,0,-hw));

		TexCoord(Vec2(0,0),0);				//texture coordinates
		TexCoord(Vec3(0,0,1),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(-1,0,0));
		Vertex(Vec3(hw,0,hw));
		//front wall
		TexCoord(Vec2(0, htc),0);			//texture coordinates
		TexCoord(Vec3(1,0,0),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(0,0,-1));
		Vertex(Vec3(-hw,h,hw));

		TexCoord(Vec2(tc,htc),0);			//texture coordinates
		TexCoord(Vec3(1,0,0),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(0,0,-1));
		Vertex(Vec3(hw,h,hw));

		TexCoord(Vec2(tc, 0),0);			//texture coordinates
		TexCoord(Vec3(1,0,0),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(0,0,-1));
		Vertex(Vec3(hw,0,hw));

		TexCoord(Vec2(0,0),0);				//texture coordinates
		TexCoord(Vec3(1,0,0),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(0,0,-1));
		Vertex(Vec3(-hw,0,hw));
		//back wall
		TexCoord(Vec2(0, htc),0);			//texture coordinates
		TexCoord(Vec3(1,0,0),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(0,0,1));
		Vertex(Vec3(hw,h,-hw));

		TexCoord(Vec2(tc,htc),0);			//texture coordinates
		TexCoord(Vec3(1,0,0),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(0,0,1));
		Vertex(Vec3(-hw,h,-hw));

		TexCoord(Vec2(tc, 0),0);			//texture coordinates
		TexCoord(Vec3(1,0,0),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(0,0,1));
		Vertex(Vec3(-hw,0,-hw));

		TexCoord(Vec2(0,0),0);				//texture coordinates
		TexCoord(Vec3(1,0,0),1);			//tangent
		TexCoord(Vec3(0,1,0),2);			//bitangent
		Normal(Vec3(0,0,1));
		Vertex(Vec3(hw,0,-hw));		
	glEnd();

}
void DrawPrism(float x, float y, float z)
{
	double hx=x/2.0f, hy=y/2.0f, hz=z/2.0f;
	glBegin(GL_QUADS);
        glColor4f(1, 1, 1, 1);

        // face v0-v1-v2-v3
        glNormal3f(0,0,1);
        glTexCoord2f(1, 1);  glVertex3f(hx,hy,hz);
        glTexCoord2f(0, 1);  glVertex3f(-hx,hy,hz);
        glTexCoord2f(0, 0);  glVertex3f(-hx,-hy,hz);
        glTexCoord2f(1, 0);  glVertex3f(hx,-hy,hz);

        // face v0-v3-v4-v5
        glNormal3f(1,0,0);
        glTexCoord2f(0, 1);  glVertex3f(hx,hy,hz);
        glTexCoord2f(0, 0);  glVertex3f(hx,-hy,hz);
        glTexCoord2f(1, 0);  glVertex3f(hx,-hy,-hz);
        glTexCoord2f(1, 1);  glVertex3f(hx,hy,-hz);

        // face v0-v5-v6-v1
        glNormal3f(0,1,0);
        glTexCoord2f(1, 0);  glVertex3f(hx,hy,hz);
        glTexCoord2f(1, 1);  glVertex3f(hx,hy,-hz);
        glTexCoord2f(0, 1);  glVertex3f(-hx,hy,-hz);
        glTexCoord2f(0, 0);  glVertex3f(-hx,hy,hz);

        // face  v1-v6-v7-v2
        glNormal3f(-1,0,0);
        glTexCoord2f(1, 1);  glVertex3f(-hx,hy,hz);
        glTexCoord2f(0, 1);  glVertex3f(-hx,hy,-hz);
        glTexCoord2f(0, 0);  glVertex3f(-hx,-hy,-hz);
        glTexCoord2f(1, 0);  glVertex3f(-hx,-hy,hz);

        // face v7-v4-v3-v2
        glNormal3f(0,-1,0);
        glTexCoord2f(0, 0);  glVertex3f(-hx,-hy,-hz);
        glTexCoord2f(1, 0);  glVertex3f(hx,-hy,-hz);
        glTexCoord2f(1, 1);  glVertex3f(hx,-hy,hz);
        glTexCoord2f(0, 1);  glVertex3f(-hx,-hy,hz);

        // face v4-v7-v6-v5
        glNormal3f(0,0,-1);
        glTexCoord2f(0, 0);  glVertex3f(hx,-hy,-hz);
        glTexCoord2f(1, 0);  glVertex3f(-hx,-hy,-hz);
        glTexCoord2f(1, 1);  glVertex3f(-hx,hy,-hz);
        glTexCoord2f(0, 1);  glVertex3f(hx,hy,-hz);
    glEnd();
}
void DrawEnvCube(double size)
{
	double half_size=size/2;
	glBegin(GL_QUADS);
        glColor4f(1, 1, 1, 1);

        // face v0-v1-v2-v3
        glNormal3f(0,0,1);
        glTexCoord3f(1, 1, 1);  glVertex3f(half_size,half_size,half_size);
        glTexCoord3f(-1, 1, 1);  glVertex3f(-half_size,half_size,half_size);
        glTexCoord3f(-1, -1, 1);  glVertex3f(-half_size,-half_size,half_size);
        glTexCoord3f(1, -1, 1);  glVertex3f(half_size,-half_size,half_size);

        // face v0-v3-v4-v5
        glNormal3f(1,0,0);
        glTexCoord3f(1, 1, 1);  glVertex3f(half_size,half_size,half_size);
        glTexCoord3f(1, -1, 1);  glVertex3f(half_size,-half_size,half_size);
        glTexCoord3f(1, -1, -1);  glVertex3f(half_size,-half_size,-half_size);
        glTexCoord3f(1, 1, -1);  glVertex3f(half_size,half_size,-half_size);

        // face v0-v5-v6-v1
        glNormal3f(0,1,0);
        glTexCoord3f(1, 1, 1);  glVertex3f(half_size,half_size,half_size);
        glTexCoord3f(1, 1, -1);  glVertex3f(half_size,half_size,-half_size);
        glTexCoord3f(-1, 1, -1);  glVertex3f(-half_size,half_size,-half_size);
        glTexCoord3f(-1, 1, 1);  glVertex3f(-half_size,half_size,half_size);

        // face  v1-v6-v7-v2
        glNormal3f(-1,0,0);
        glTexCoord3f(-1, 1, 1);  glVertex3f(-half_size,half_size,half_size);
        glTexCoord3f(-1, 1, -1);  glVertex3f(-half_size,half_size,-half_size);
        glTexCoord3f(-1, -1, -1);  glVertex3f(-half_size,-half_size,-half_size);
        glTexCoord3f(-1, -1, 1);  glVertex3f(-half_size,-half_size,half_size);

        // face v7-v4-v3-v2
        glNormal3f(0,-1,0);
        glTexCoord3f(-1, -1, -1);  glVertex3f(-half_size,-half_size,-half_size);
        glTexCoord3f(1, -1, -1);  glVertex3f(half_size,-half_size,-half_size);
        glTexCoord3f(1, -1, 1);  glVertex3f(half_size,-half_size,half_size);
        glTexCoord3f(-1, -1, 1);  glVertex3f(-half_size,-half_size,half_size);

        // face v4-v7-v6-v5
        glNormal3f(0,0,-1);
        glTexCoord3f(1, -1, -1);  glVertex3f(half_size,-half_size,-half_size);
        glTexCoord3f(-1, -1, -1);  glVertex3f(-half_size,-half_size,-half_size);
        glTexCoord3f(-1, 1, -1);  glVertex3f(-half_size,half_size,-half_size);
        glTexCoord3f(1, 1, -1);  glVertex3f(half_size,half_size,-half_size);
    glEnd();
}
void Normal(Vec3 normal)
{
	glNormal3f(normal.x, normal.y, normal.z);
}
void Vertex(Vec3 vertex)
{
	glVertex3f(vertex.x, vertex.y, vertex.z);
}
Vec3 getAxis(Vec3 from, Vec3 to)
{
	Vec3 norm;
	from.normalize();
	to.normalize();
	norm=from.cross(to);
	return norm;
}
Quat getQuat(Vec3 dir)
{
	Vec3 axis=getAxis(Vec3(1,0,0), dir);
	float angle=std::asin(axis.magnitude());
	axis.normalize();
	Quat q=Quat(axis, angle);
	return q;
}
std::pair<Mat44,Mat44> GetWorldPair(Vec3 pos, Rotator rot)
{
	Mat44 trans_mat, rot_mat, final_mat;
	std::pair<Mat44,Mat44> pair;
	Mat33 quat_mat=(Mat33)((Quat)rot);
	//calculate trans mat
	trans_mat.set_translate(NVec3(pos.x, pos.y, pos.z));
	//calculate rot mat
	for(unsigned int i=0;i<3;i++)
	{
		Vec3 v=quat_mat.getRow(i);
		rot_mat.set_row(i, Vec4(v.x, v.y, v.z, 0));
	}
	rot_mat.set_row(3, Vec4(0,0,0,1));
	pair.first=trans_mat;
	pair.second=rot_mat;
	return pair;
}
Mat44 CalculateWorldMatrix(Vec3 pos, Rotator rot)
{
	std::pair<Mat44, Mat44> pair=GetWorldPair(pos, rot);
	Mat44 final_mat=pair.first*pair.second;
	return final_mat;
}
Mat44 TranslationMatrix(Vec3 v)
{
	Mat44 trans_mat;
	trans_mat.set_translate(NVec3(v.x,v.y,v.z));
	return trans_mat;
}
Mat44 RotationMatrix(Quat rot)
{
	Mat44 rot_mat;
	Mat33 quat_mat=(Mat33)(rot);
	for(unsigned int i=0;i<3;i++)
	{
		Vec3 v=quat_mat.getRow(i);
		rot_mat.set_row(i, Vec4(v.x, v.y, v.z, 0));
	}
	rot_mat.set_row(3, Vec4(0,0,0,1));
	return rot_mat;
}
Mat44 ScalingMatrix(Vec3 v)
{
	Mat44 scale_mat;
	scale_mat.set_scale(NVec3(v.x,v.y,v.z));
	return scale_mat;
}
Mat44 ViewMatrix(Vec3 eye, Vec3 center, Vec3 up)
{
	Mat44 view_mat, trans_mat;
	Vec3 L=center-eye;
	L.normalize();
	up.normalize();
	Vec3 S=L.cross(up);
	S.normalize();
	Vec3 U=S.cross(L);
	view_mat.set_row(0,Vec4(S.x,S.y,S.z,0));
	view_mat.set_row(1,Vec4(U.x,U.y,U.z,0));
	view_mat.set_row(2,Vec4(-L.x,-L.y,-L.z,0));
	view_mat.set_row(3,Vec4(0,0,0,1));

	trans_mat.set_translate(NVec3(-eye.x,-eye.y,-eye.z));
	return view_mat*trans_mat;
}
Mat44 ProjectionMatrix(double fov, double aspect, double nvp, double fvp)
{
	double f=1/std::tan(fov*PI/(180*2));
	Mat44 proj_mat;
	proj_mat.set_column(0,Vec4(f/aspect,0,0,0));
	proj_mat.set_column(1,Vec4(0,f,0,0));
	proj_mat.set_column(2,Vec4(0,0,(nvp+fvp)/(nvp-fvp),-1));
	proj_mat.set_column(3,Vec4(0,0,2*fvp*nvp/(nvp-fvp),0));
	return proj_mat;
}
Mat44 BiasMatrix(real bias)
{
	Mat44 bias_matrix;
	bias_matrix.set_column(0, Vec4(bias,0,0,0));
	bias_matrix.set_column(1, Vec4(0,bias,0,0));
	bias_matrix.set_column(2, Vec4(0,0,bias,0));
	bias_matrix.set_column(3, Vec4(bias,bias,bias,1));
	return bias_matrix;
}
Mat44 GetModelViewProj()
{
	Mat44 mat, modelview, proj;
	return mat;
}
void Draw6Toruses(double radius)
{
	Vec3 color[6]={Vec3(1,0,0),Vec3(1,1,0),Vec3(0,1,0),Vec3(0,1,1),Vec3(0,0,1),Vec3(1,0,1)};
	Vec3 translate[6]={Vec3(1,0,0),Vec3(-1,0,0),Vec3(0,1,0),Vec3(0,-1,0),Vec3(0,0,1),Vec3(0,0,-1)};
	for(unsigned int i=0;i<6;i++)
	{
		glPushMatrix();
			glColor3f(color[i].x,color[i].y,color[i].z);
			glTranslatef(translate[i].x*radius,translate[i].y*radius,translate[i].z*radius);
			glutSolidTorus(1, 2, 32, 32);
		glPopMatrix();
	}
}
void DrawRainbow(double radius, int nElements)
{
	real rotate_step=PI*2/nElements, rotation=0;
	for(int i=0;i<nElements;i++)
	{
		real r,g,b;
		r=std::abs(std::sin(rotation));
		g=std::abs(std::sin(rotation+PI/3));
		b=std::abs(std::sin(rotation+2*PI/3));
		glPushMatrix();
			glColor3f(r,g,b);
			glTranslatef(std::cos(rotation)*radius, 0, std::sin(rotation)*radius);
			glutSolidTorus(1, 2, 32, 32);
		glPopMatrix();
		rotation+=rotate_step;
	}

}
string GetCGErrs()
{
	CGerror error;
	string error_str;
	while((error = cgGetError()) != CG_NO_ERROR)
	{
		error_str<<=string(" ")<<cgGetErrorString(error)<<";";
	}
	if(!error_str.empty())
		error_str=" CG: "<<error_str;
	return error_str;
}
string GetGLErrs()
{
	GLenum error;
	string error_str;
	while((error = glGetError()) != GL_NO_ERROR)
		error_str<<=" "<<string((const char*)gluErrorString(error))<<";";
	if(!error_str.empty())
		error_str=" GL: "<<error_str;
	return error_str;
}
string GetILErrs()
{
	ILenum error;
	string error_str;
	while((error = ilGetError()) != IL_NO_ERROR)
		error_str<<=" "<<string::intToAlpha(error)<<";";
	if(!error_str.empty())
		error_str=" IL: "<<error_str;
	return error_str;
}
void ThrowError(string str)
{
	string error_str=GetILErrs()<<GetGLErrs()<<GetCGErrs();
	if(!error_str.empty())
	{
		str<<=error_str;
		_log(str);
		throw BException(str);
	}
}
void ReportError(string str)
{
	string error_str=GetILErrs()<<GetGLErrs()<<GetCGErrs();
	if(!error_str.empty())
	{
		str<<=error_str;
		_log(str);
	}
}
void ReportError_IL(string str)
{
	string error_str=GetILErrs();
	if(!error_str.empty())
	{
		str<<=error_str;
		_log(str);
	}
}
void ReportError_GL(string str)
{
	string error_str=GetGLErrs();
	if(!error_str.empty())
	{
		str<<=error_str;
		_log(str);
	}
}
void ReportError_CG(string str)
{
	string error_str=GetCGErrs();
	if(!error_str.empty())
	{
		str<<=error_str;
		_log(str);
	}
}
void TestDraw()
{
	/*static double angle;
	angle+=1;
	sptr<GameResource> shader_resc=_RESC("Basic_Shader");
	Shader* shader=_SHADER(shader_resc);
	sptr<Actor> light=_ACTOR("Light1");
	sptr<Actor> pawn_actor=_ACTOR("Sword");
	Pawn* pawn=_PAWN(pawn_actor);
	Model* model=_MODEL(pawn->Models[0]->Model);
	Mesh* mesh=_MESH(model->Mesh);
	if(shader)
	{	
		shader->LoadTexture("EnvSampler", globals.Graphics.EnvMap);
		shader->SetReal("EtaRatio", .1);
		shader->LoadTexture("ShadowSampler", globals.Graphics.ShadowMap);
		shader->LightActor=light;
		
		shader->Translation=Vec3(0,0,20);
		//shader->Rotation=Rotator(-angle,-90);
		shader->Rotation=(Quat)Rotator();
		shader->MainCamera=_MAIN_CAMERA;
		shader->LoadTexture("DiffuseSampler", globals.Graphics.DeferredMap);
		shader->BeginPass("p0");
			//mesh->Draw();
			DrawCube(10);
			//DrawEnvCube(10);
			//glutSolidTeapot(10);
			//glutSolidSphere(20,32,32);
		shader->EndPass();
		/*shader=_SHADER(_RESC("Basic_Shader"));
		shader->Rotation=Rotator();
		shader->Translation=Vec3(20,0,0);
		shader->MainCamera=_MAIN_CAMERA;
		shader->LoadTexture("DiffuseSampler",globals.Graphics.NormalMap);
		shader->BeginPass("p0");
			DrawCube(10);
		shader->EndPass();
		shader->Translation=Vec3(-20,0,0);
		shader->LoadTexture("DiffuseSampler",globals.Graphics.SpecularMap);
		shader->BeginPass("p0");
			DrawCube(10);
		shader->EndPass();
		shader->Translation=Vec3(0,20,0);
		shader->LoadTexture("DiffuseSampler",globals.Graphics.ViewVecMap);
		shader->BeginPass("p0");
			DrawCube(10);
		shader->EndPass();
		shader->Translation=Vec3(0,-20,0);
		shader->LoadTexture("DiffuseSampler",globals.Graphics.DepthMap);
		shader->BeginPass("p0");
			DrawCube(10);
		shader->EndPass();
		shader->Translation=Vec3(-20,20,0);
		shader->LoadTexture("DiffuseSampler",globals.Graphics.ShadowMap);
		shader->BeginPass("p0");
			DrawCube(10);
		shader->EndPass();
		shader->Translation=Vec3(20,20,0);
		shader->LoadTexture("DiffuseSampler",globals.Graphics.LightVecMap);
		shader->BeginPass("p0");
			DrawCube(10);
		shader->EndPass();
		shader->Translation=Vec3(-20,-20,0);
		shader->LoadTexture("DiffuseSampler",globals.Graphics.TotalLightMap[globals.Graphics.GetCurLightMapID()]);
		shader->BeginPass("p0");
			DrawCube(10);
		shader->EndPass();
		shader->Translation=Vec3(20,-20,0);
		shader->LoadTexture("DiffuseSampler",globals.Graphics.TotalSpecularMap[globals.Graphics.GetCurLightMapID()]);
		shader->BeginPass("p0");
			DrawCube(10);
		shader->EndPass();
		shader->Translation=Vec3(0,0,0);
		shader->LoadTexture("DiffuseSampler",globals.Graphics.DiffuseMap);
		shader->BeginPass("p0");
			DrawCube(10);
		shader->EndPass();
	}*/
}